#ifndef __RTCSclient_H_
#define __RTCSclient_H_

#include "RTCSgor.h"
#include "RTCStype.h"
#include "RTCSpdu.h"
#include "RTCSerror.h"
#include "RTCSserver.h"
#include "IClientBase.h"
#include "RTCSbaseObject.h"
#include "TraceLog.h"

typedef RTCS_SimpleQueue<RTCS_CTpdu> RTCS_PduSimpleQueue;

//##ModelId=3AAC610C0340
class RTCS_Client{
public:
	//##ModelId=3AAC610D00C1
	RTCS_Client(RTCS_CTuint handle, RTCS_CTstring clientname);
	//##ModelId=3AAC610D00B8
	virtual ~RTCS_Client();

	//##ModelId=3AAC610D00B7
	RTCS_CTuint		GetGOR();
	//##ModelId=3AAC610D00AD
	void			UseBus(RTCS_Server* server);
	//##ModelId=3AAC610D0085
	RTCS_CTuint		SetTimer(RTCS_CTuint owner, RTCS_CTuint delay, RTCS_CTuint attr=0);
	//##ModelId=3AAC610D007B
	void			ClearTimer(RTCS_CTuint timerID);
	//##ModelId=3AAC610D0068
	RTCS_CTuint		PostMessage(RTCS_CTpdu& pdu, RTCS_CTbool callFromOtherThread = RTCS_CTboolFALSE);

	RTCS_CTuint		BroadCastMessage(RTCS_CTpdu& pdu);
	//##ModelId=3AAC610D0067
	RTCS_CTuint		InsertBus();
	void			DistachBus();
	//##ModelId=3AAC610D0053
	RTCS_CTbool		IsClientOnline(RTCS_CTstring _clientname);
	//##ModelId=3AAC610D0049
	RTCS_CTuint		GetRemoteGOR(RTCS_CTstring _name);
	//##ModelId=3AAC610D003F
	RTCS_CTuint		GetRemoteStation(RTCS_CTstring _stationname);
	//##ModelId=3AAC610D0036
	RTCS_CTuint		GetStationNo();
	//##ModelId=3AAC610D0035
	HANDLE			GetHandle();
	
	//##ModelId=3AAC610D002B
	virtual RTCS_CTuint HandleMessage(RTCS_CTpdu& pdu) = 0;
	
	//##ModelId=3AAC610D0021
	virtual RTCS_CTuint OnBusInserted(){return RTCS_Error_OK;}
	//##ModelId=3AAC610D0017
	virtual RTCS_CTuint OnClientOnline(RTCS_CTstring clientname){return	RTCS_Error_OK;}
	//##ModelId=3AAC610D0004
	virtual RTCS_CTuint OnClientOffline(RTCS_CTstring clientname){return RTCS_Error_OK;}
	//##ModelId=3AAC610D0003
	virtual RTCS_CTuint OnBusDisAttached(){return RTCS_Error_OK;}
	//##ModelId=3AAC610C03E1
	virtual RTCS_CTuint OnBusShutDown(){return RTCS_Error_OK;}
	//##ModelId=3AAC610C03D7
	virtual RTCS_CTuint OnTimer(RTCS_CTpdu& pdu){return RTCS_Error_OK;}

	//##ModelId=3AAC610C03A7
	RTCS_CTuint		coh;			// client object handle
	//##ModelId=3AAC610C039B
	RTCS_CTstring	name;

private:
	//##ModelId=3AAC610C03CD
	void					UseTimer(RTCS_MultiTimer* timer);
	//##ModelId=3AAC610C03B9
	RTCS_CTuint				PollMessage(RTCS_CTpdu& pdu);
	//##ModelId=3AAC610C03B0
	RTCS_CTuint				Run();
	//##ModelId=3AAC610C03AF
	RTCS_CTuint				DoRun();

	//##ModelId=3AAC610C0388
	RTCS_MultiTimer*		pTimer;
	//##ModelId=3AAC610C037C
	RTCS_Thread*			thread;
	//##ModelId=3AAC610C036A
	RTCS_PduSimpleQueue*	queue;
	//##ModelId=3AAC610C0360
	RTCS_Server*			bus;
	//##ModelId=3AAC610C034E
	RTCS_TraceLog*			log;

	//##ModelId=3AAC610C034A
	friend RTCS_CTuint do_Run(RTCS_Client* client)
	{
		return client ? client->DoRun() : RTCS_Error_ECTF_Fail;
	}
	friend RTCS_Server;
};


/**************************\
** inline implementations **
\**************************/

inline RTCS_CTuint RTCS_Client::GetGOR()
{
	if( bus == NULL ) return INVALID_GOR;
	return bus->IsRegisted() ? MAKEGOR(bus->stationNo,coh) : coh;
}

inline void RTCS_Client::UseBus(RTCS_Server* server)
{	
	bus = server;	
	if( server->logdir == "" )
		log=new RTCS_TraceLog( name + ".log", 1 ,1000000);
	else
		log = new RTCS_TraceLog( server->logdir + "//" + name + ".log", 1, 1000000 );
	log->Trace(1, "[%s] client is comming now...\n",(LPCTSTR)name);
}

inline void RTCS_Client::UseTimer(RTCS_MultiTimer* timer)
{	
	pTimer = timer;	
}

inline RTCS_CTuint RTCS_Client::SetTimer(RTCS_CTuint owner, RTCS_CTuint delay, RTCS_CTuint attr)
{	
	return pTimer ? (pTimer->SetTimer(owner, delay,attr)) : 0;	
}

inline void RTCS_Client::ClearTimer(RTCS_CTuint timerID)
{	
	if(pTimer) (pTimer->ClearTimer(timerID));	
}

inline RTCS_Client::RTCS_Client(RTCS_CTuint handle, RTCS_CTstring clientname)
	: bus(NULL),pTimer(NULL),coh(handle),name(clientname),queue(NULL),log(NULL)
{
	queue=new RTCS_PduSimpleQueue(RTCS_QUEUESIZE); 
	thread = new RTCS_Thread((RTCS_THREADFUNC)do_Run,this);
}

inline RTCS_CTuint RTCS_Client::PostMessage(RTCS_CTpdu& pdu, RTCS_CTbool callFromOtherThread)
{
	if(pdu.receiver==GetGOR() && callFromOtherThread!=RTCS_CTboolTRUE)
		return queue->Put(pdu);

	if(bus) 
	{
		//log->Trace(1, " <----- send 0x%08X [0x%08X <- 0x%08X]\n", pdu.messageID, pdu.receiver, pdu.sender);
		return bus->ClientSend(pdu);
	}

	return RTCS_Error_ECTF_Fail;
}

inline RTCS_CTuint RTCS_Client::BroadCastMessage(RTCS_CTpdu& pdu)
{
	if(bus) 
	{
		//log->Trace(1, " <----- broadcast 0x%08X [0x%08X <- 0x%08X]\n", pdu.messageID, pdu.receiver, pdu.sender);
		return bus->BroadcastChannel->queue.Put(pdu);
	}

	return RTCS_Error_ECTF_Fail;
}

inline RTCS_CTuint RTCS_Client::InsertBus()
{
	if(bus)
	{
		RTCS_CTuint rc = bus->InsertBus(this);
		if(rc == RTCS_Error_OK)
			log->Trace(1, " InsertBus(), OK\n");
		else
			log->Trace(1, " InsertBus(), ERROR: error no = %d\n", rc);
		return rc;
	}
	else
	{
		log->Trace(1, " InsertBus(), ERROR: no bus\n");
		return RTCS_Error_NoBus;	
	}
}

inline void RTCS_Client::DistachBus()
{
	if(bus)
	{
		bus->DistachBus(this);
		log->Trace(1, " DistachBus(), OK\n");
	}
	else
		log->Trace(1, " DistachBus(), ERROR: no bus\n");
}

inline RTCS_CTuint RTCS_Client::GetStationNo()
{
	if( bus == NULL ) return INVALID_STATION;
	return bus->stationNo;
}

inline HANDLE RTCS_Client::GetHandle()
{
	return thread? thread->GetHandle() : 0;
}

inline RTCS_CTuint RTCS_Client::Run()
{
	return thread? thread->Resume() : RTCS_Error_ECTF_Fail;
}

#endif
